package com.corpdata.core.config;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authz.UnauthorizedException;
import org.mortbay.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.alibaba.fastjson.JSON;
import com.corpdata.common.enums.HttpCodeEnum;
import com.corpdata.common.result.Result;
import com.corpdata.common.utils.CorpdataUtil;
import com.corpdata.core.exception.ServiceException;
import com.corpdata.system.error.entity.SysHttpError;
import com.corpdata.system.error.service.SysHttpErrorService;
import com.corpdata.system.security.shiro.util.UserUtil;

/**
 * Spring MVC 配置
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    private final Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);

    //上传附件物理文件夹目录
    @Value("${web.upload.file_path}")
    private String uploadFolder;

    //上传附件web访问目录
    @Value("${web.upload.access_path}")
    private String uploadAccessPath;

    @Value("${spring.profiles.active}")
    private String env;//当前激活的配置文件
    
    @Autowired
    private SysHttpErrorService sysHttpErrorService;

    //注册web文件资源访问地址
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        logger.info("uploadAccessPath:"+uploadAccessPath+"   ,uploadFolder:"+uploadFolder);
        registry.addResourceHandler(uploadAccessPath).addResourceLocations("file:" + uploadFolder);
    }

    //统一异常处理
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add((HttpServletRequest request, HttpServletResponse response, Object handler, Exception e)-> {
                Result result = new Result();
                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”
                	result.setCode(HttpCodeEnum.FAIL.getCode());
                	result.setError(e.getMessage());
                    result.setMessage(e.getMessage());
                    logger.info(e.getMessage());
                } else if (e instanceof NoHandlerFoundException) {
                	result.setCode(HttpCodeEnum.NOT_FOUND.getCode());
                	result.setError("服务 [" + request.getRequestURI() + "] 不存在");
                    result.setMessage("服务 [" + request.getRequestURI() + "] 不存在");
                } else if (e instanceof ServletException) {
                	result.setCode(HttpCodeEnum.FAIL.getCode());
                	result.setError(e.getMessage());
                    result.setMessage(e.getMessage());
                } else if(e instanceof UnauthorizedException){//shiro 无权限异常
                    Log.debug("{}用户无权限使用{}资源",UserUtil.getCurrentUserid(),request.getRequestURI());
                    
                    ModelAndView modelAndView = new ModelAndView();
                    modelAndView.setViewName("common/error/404");
                    
                    return modelAndView;
                }else {
                	result.setCode(HttpCodeEnum.INTERNAL_SERVER_ERROR.getCode());
                	result.setError("服务 [" + request.getRequestURI() + "] 内部错误，请联系管理员");
                    result.setMessage("服务内部错误，请联系管理员");
                    String message;
                    String errorMethod = "";
                    String errorServiceUrl="";
                    if (handler instanceof HandlerMethod) {
                        HandlerMethod handlerMethod = (HandlerMethod) handler;
                        message = String.format("服务 [%s] 出现异常，方法：%s.%s，异常摘要：%s",
                                request.getRequestURI(),
                                handlerMethod.getBean().getClass().getName(),
                                handlerMethod.getMethod().getName(),
                                e.getMessage());
                        errorMethod = handlerMethod.getBean().getClass().getName()+"."+handlerMethod.getMethod().getName();
                        errorServiceUrl=request.getRequestURI();
                    } else {
                        message = e.getMessage();
                    }
                    logger.error(message, e);
                    
                    //存储异常到数据库
                    SysHttpError record = new SysHttpError();
                    record.setErrorMessage(message);
                    record.setErrorServiceUrl(errorServiceUrl);
                    record.setErrorServiceMethod(errorMethod);
                    record.setIpAddress(CorpdataUtil.getIpAddress(request));
                    sysHttpErrorService.save(record);
                }
                responseResult(response, result);
                
                return null;
            }
        );
    }

    //解决跨域问题
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //registry.addMapping("/**");
    }
    
    /**
     * 拦截器  负责控制小程序的登录验证
     */
    @Override
	public void addInterceptors(InterceptorRegistry registry) {
	}

	private void responseResult(HttpServletResponse response, Result result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            logger.error(ex.getMessage());
        }
    }
}
